#include <cserver/iom.h>
namespace csrv{ 

	bool in_size_t_range(size_t n){
		return (n & ~size_t(size_t(-1))) == 0;
	}

	/// buffer_in
	buffer_in::buffer_in(const std::vector<char>& buf)
		: m_pos(0), m_data(to_range(buf))
	{ }

	buffer_in::buffer_in(const range<const char*>& buf)
		: m_pos(0), m_data(buf)
	{ }

	range<buffer_in::iterator> buffer_in::read(const range<buffer_in::iterator>& buf)
	{
		auto sitr = m_data.begin() + m_pos;
		auto ditr = buf.begin();
		for (; sitr != m_data.end() && ditr != buf.end();++sitr, ++ditr)
		{
			*ditr = *sitr;
		}
		m_pos = sitr - m_data.begin();
		return range<buffer_in::iterator>(ditr, buf.end());
	}

	bool buffer_in::readable() const
	{
		return m_pos < m_data.size();
	}

	size_t buffer_in::offset() const { return m_pos;}
	size_t buffer_in::size() const { return m_data.size();}
	size_t buffer_in::seek(size_t offset)
	{
		//assert(in_size_t_range(offset));
		m_pos = (size_t)std::min(size(), offset);
		return m_pos;
	}

	range<const char*> buffer_in::data() const { return m_data;}

	/// fixed_buffer_io
	fixed_buffer_io::fixed_buffer_io(const range<char*>& buf)
		: m_pos(0), m_data(buf)
	{ }

	range<char*> fixed_buffer_io::read(const range<char*>& buf){
		auto sitr = m_data.begin() + m_pos;
		auto ditr = buf.begin();
		for (; sitr != m_data.end() && ditr != buf.end();++sitr, ++ditr)
		{
			*ditr = *sitr;
		}
		m_pos = sitr - m_data.begin();
		return range<fixed_buffer_io::iterator>(ditr, buf.end());
	}
	bool fixed_buffer_io::readable() const{
		return m_pos < m_data.size();
	}
	range<const char*> fixed_buffer_io::write(const range<const char*>& r)
	{
		auto ditr = m_data.begin() + m_pos;
		auto sitr = r.begin();
		for (; sitr != r.end() && ditr != m_data.end(); ++sitr, ++ditr)
		{
			*ditr = *sitr;
		}
		m_pos = ditr - m_data.begin();
		return range<const char*>(sitr, r.end());
	}

	bool fixed_buffer_io::writable() const { 
		return m_pos < m_data.size();
	}

	size_t fixed_buffer_io::truncate(size_t )
	{
		//assert(in_size_t_range(size));
		return unknow_size;
	}


	void fixed_buffer_io::sync() {}

	size_t fixed_buffer_io::offset() const { return m_pos;}
	size_t fixed_buffer_io::size() const { return m_data.size();}
	size_t fixed_buffer_io::seek(size_t offset)
	{
		//assert(in_size_t_range(offset));
		if (offset >= size())
			offset = size();
		m_pos = (size_t)offset;
		return m_pos;
	}

	range<char*> fixed_buffer_io::data() const { return m_data;}


	/// buffer_out
	buffer_out::buffer_out(std::vector<char>& buf)
		: m_pos(0), m_data(&buf)
	{ }

	range<const char*> buffer_out::write(const range<const char*>& r)
	{
		if (!r.empty())
		{
			if (m_pos > m_data->size())
				m_data->resize(m_pos);

			auto ditr = m_data->begin() + m_pos;
			auto sitr = r.begin();
			for (; sitr != r.end() && ditr != m_data->end(); ++sitr, ++ditr)
			{
				*ditr = *sitr;
			}
			if (sitr != r.end())
			{
				m_data->insert(m_data->end(), sitr, r.end());
				m_pos = m_data->size();
			}
			else
				m_pos = ditr - m_data->begin();
		}
		return range<const char*>(r.end(), r.end());

	}

	size_t buffer_out::truncate(size_t size)
	{
		//assert(in_size_t_range(size));

		m_pos = std::min(m_pos, (size_t)size);
		m_data->resize((size_t)size);
		return size;
	}

	bool buffer_out::writable() const { return true;}

	void buffer_out::sync() {}

	size_t buffer_out::offset() const { return m_pos;}
	size_t buffer_out::size() const { return m_data->size();}
	size_t buffer_out::seek(size_t offset)
	{
		//assert(in_size_t_range(offset));
		m_pos = (size_t)offset;
		return m_pos;
	}

	std::vector<char> & buffer_out::data() { return *m_data;}
	const std::vector<char> & buffer_out::data() const { return *m_data;}

	/// buffer_io

	buffer_io::buffer_io(std::vector<char>& buf)
		: m_pos(0), m_data(&buf)
	{ }

	range<char*> buffer_io::read(const range<char*>& buf)
	{
		if (m_pos > m_data->size())
			return buf;

		auto sitr = m_data->begin() + m_pos;
		auto ditr = buf.begin();
		for (; sitr != m_data->end() && ditr != buf.end();++sitr, ++ditr)
		{
			*ditr = *sitr;
		}
		m_pos = sitr - m_data->begin();
		return range<char*>(ditr, buf.end());
	}

	bool buffer_io::readable() const
	{
		return m_pos < m_data->size();
	}

	range<const char*> buffer_io::write(const range<const char*>& r)
	{
		if (!r.empty())
		{
			if (m_pos > m_data->size())
				m_data->resize(m_pos);

			auto ditr = m_data->begin() + m_pos;
			auto sitr = r.begin();
			for (; sitr != r.end() && ditr != m_data->end(); ++sitr, ++ditr)
			{
				*ditr = *sitr;
			}
			if (sitr != r.end())
			{
				m_data->insert(m_data->end(), sitr, r.end());
				m_pos = m_data->size();
			}
			else
				m_pos = ditr - m_data->begin();
		}
		return range<const char*>(r.end(), r.end());

	}

	size_t buffer_io::truncate(size_t size)
	{
		//assert(in_size_t_range(size));
		m_pos = std::min(m_pos, (size_t)size);
		m_data->resize((size_t)size);
		return size;
	}

	bool buffer_io::writable() const { return true;}
	void buffer_io::sync() {}

	size_t buffer_io::offset() const { return m_pos;}
	size_t buffer_io::size() const { return m_data->size(); }
	size_t buffer_io::seek(size_t offset) { 
		//assert(in_size_t_range(offset));
		return m_pos = (size_t)offset;
	}

	std::vector<char> & buffer_io::data() { return *m_data;}
	const std::vector<char> & buffer_io::data() const { return *m_data;}

	/// mem_read_archive
	mem_writer::mem_writer() : buffer_out(m_data){}
    mem_writer::mem_writer(const mem_writer& rhs)
        : buffer_out(m_data)
        , m_data(rhs.m_data){
    }
    mem_writer::mem_writer(mem_writer&& rhs)
        : buffer_out(m_data)
        , m_data(std::forward<std::vector<char>>(rhs.m_data)){
    }
    
    mem_writer& mem_writer::operator=(const mem_writer& rhs){
        if (this != &rhs)
            m_data = rhs.m_data;
        return *this;
    }
    mem_writer& mem_writer::operator=(mem_writer&& rhs){
        m_data = std::forward<std::vector<char>>(rhs.m_data);
        return *this;
    }
    
	mem_archive::mem_archive() : buffer_io(m_data){}
	mem_archive::mem_archive(const std::vector<char>& buf) : buffer_io(m_data) { m_data = buf; }
    
    mem_archive::mem_archive(mem_archive&& rhs)
        : buffer_io(m_data)
        , m_data(std::forward<std::vector<char>>(rhs.m_data))
    {
    }
    mem_archive::mem_archive(const mem_archive& rhs)
        : buffer_io(m_data)
        , m_data(rhs.m_data)
    {}
    
    mem_archive& mem_archive::operator=(const mem_archive& rhs){
        if (this != &rhs)
            m_data = rhs.m_data;
        return *this;
    }
    mem_archive& mem_archive::operator=(mem_archive&& rhs){
        m_data = std::forward<std::vector<char>>(rhs.m_data);
        return *this;
    }

	/// zero
	zero::zero(): m_pos(0){}
	range<char*> zero::read(const range<char*>& buf){
		std::fill(buf.begin(), buf.end(), char(0));
		m_pos += buf.size();
		return range<char*>(buf.end(), buf.end());
	}
	bool zero::readable() const { return true;}

	size_t zero::offset() const{ return m_pos;}
	size_t zero::size() const{ return unknow_size;}
	size_t zero::seek(size_t off){ return m_pos = off;}

	/// null
	null::null() : m_pos(0){}

	range<const char*> null::write(const range<const char*>& r){
		m_pos += r.size();
		return range<const char*>(r.end(), r.end());
	}
	bool null::writable() const{ return true;}
	void null::sync() {}

	size_t null::offset() const{ return m_pos;}
	size_t null::size() const{ return unknow_size;}
	size_t null::seek(size_t off){
		return m_pos = off;
	} 
	size_t null::truncate(size_t ){ return unknow_size;}

	/// empty
	range<char*> empty::read(const range<char*>& buf){ return buf; }
	bool empty::readable() const{ return false; }
	size_t empty::offset() const{ return 0;}
	size_t empty::size() const { return 0;}
	size_t empty::seek(size_t /*offset*/) { return 0;}
}

